package com.lry.jvm.instructions.refrences;

import com.lry.jvm.instructions.base.Index16Instruction;
import com.lry.jvm.rtda.Frame;
import com.lry.jvm.rtda.JObject;
import com.lry.jvm.rtda.OperandStack;
import com.lry.jvm.rtda.heap.*;
import com.lry.jvm.util.Util;

public class putfield extends Index16Instruction {
    @Override
    public byte getOpCode() {
        return (byte) 0xb5;
    }

    @Override
    public void execute(Frame frame) {
        JMethod method = frame.getMethod();
        JClass jClass = method.getJClass();
        RuntimeConstantPool rcp = jClass.getConstantPool();

        FieldRef fieldRef = (FieldRef) rcp.getConstant(index);
        JField field = fieldRef.resolvedField();

        if(field.isStatic()){
            Util.panic("java.lang.IncompatibleClassChangeError");
        }

        if (field.isFinal()) {
            if (jClass != field.getJClass() || !method.getName().equals("<init>")) {
                Util.panic("java.lang.IllegalAccessError");
            }
        }

        String descriptor = field.getDescriptor();
        int slotId = field.getSlotId();
        OperandStack stack = frame.getOperandStack();

        switch (descriptor.charAt(0)){
            case 'Z':
            case 'B':
            case 'C':
            case 'S':
            case 'I':
                int iVal = stack.popInt();
                JObject iObj = stack.popRef();
                if(null==iObj){
                    Util.panic("java.lang.NullPointerException");
                }
                iObj.getInstanceVars().setInt(slotId,iVal);
                break;
            case 'F':
                float fVal = stack.popFloat();
                JObject fObj = stack.popRef();
                if(null==fObj){
                    Util.panic("java.lang.NullPointerException");
                }
                fObj.getInstanceVars().setFloat(slotId,fVal);
                break;
            case 'J':
                long lVal = stack.popLong();
                JObject lObj = stack.popRef();
                if(null==lObj){
                    Util.panic("java.lang.NullPointerException");
                }
                lObj.getInstanceVars().setLong(slotId,lVal);
                break;
            case 'D':
                double dVal = stack.popInt();
                JObject dObj = stack.popRef();
                if(null==dObj){
                    Util.panic("java.lang.NullPointerException");
                }
                dObj.getInstanceVars().setDouble(slotId,dVal);
                break;
            case '[':
            case 'L':
                JObject ref = stack.popRef();
                JObject rObj = stack.popRef();
                if(null==rObj){
                    Util.panic("java.lang.NullPointerException");
                }
                rObj.getInstanceVars().setRef(slotId,ref);
                break;
        }
    }
}
